/**
 * 
 */
package academic.ui.server;

import it.sauronsoftware.cron4j.Scheduler;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Iterator;
import java.util.List;

import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.apache.commons.configuration.ConfigurationException;
import org.apache.commons.configuration.PropertiesConfiguration;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.log4j.BasicConfigurator;
import org.apache.log4j.Level;
import org.apache.log4j.Logger;
import org.apache.torque.Torque;
import org.apache.torque.TorqueException;
import academic.ui.server.soco.PaymentInfo;
import ecommerce.soco.shared.NameValue;

import com.google.gwt.user.server.rpc.RemoteServiceServlet;


public class SocoGWTServlet extends RemoteServiceServlet
{
	
	//protected KKBeanCopier helper = new KKBeanCopier();
	
	private static final long serialVersionUID = -1474878148617384874L;

	protected Log log = LogFactory.getLog(SocoGWTServlet.class);

    
	protected HttpServletRequest request;


	/**
	 * Is this request authorized to call the servlet?
	 * 
	 * @param request
	 * @return boolean - whether the request can proceed
	 */
	public boolean authorize(HttpServletRequest request)
	{
		if(this.request==null)
			this.request = request;
		return true;
	}	
	
	public SocoGWTServlet() {
		
	}
	
	public void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{
		super.service(request, response);
		
	}
	
	private void initializeTorque() {
		  // Initializing Logging
	    BasicConfigurator.configure();
	    Logger.getRootLogger().setLevel(Level.WARN);

	    // Initializing Torque
	    
	    InputStream torqueConfigStream =  SocoGWTServlet.class.getResourceAsStream("/torque.properties");
	    PropertiesConfiguration torqueConfiguration 
	            = new PropertiesConfiguration();
	    try {
			torqueConfiguration.load(torqueConfigStream);
		} catch (ConfigurationException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	    try {
			Torque.init(torqueConfiguration);
		} catch (TorqueException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	    
	}
	
	 public void init(ServletConfig config) throws ServletException
	 {
	        // very important to call super.init() here
	        super.init(config);
	        synchronized("SocoEngineMutex") {
	        	initializeTorque();
	        }
	       
  
	 }
	 
	
	 	
		protected SocoEngine getAppEng()
	    {
	        HttpSession session = request.getSession();
	        SocoEngine socoAppEng = (SocoEngine) session.getAttribute(SocoEngine.SESSION_KEY);
	        if (socoAppEng == null)
	        {
	            //session = request.getSession();

	            if (log.isInfoEnabled())
	            {
	                log.info("Should only see this message if there is no session.");
	            }
	            socoAppEng = new SocoEngine();
	            session.setAttribute(SocoEngine.SESSION_KEY, socoAppEng);
	            return socoAppEng;
	        }

	       return socoAppEng;
	    }

	 	 protected String getExceptionMessage(Throwable e)
	     {
	         StringBuffer sb = new StringBuffer();

	         if (e.getMessage() == null)
	         {
	             sb.append("null");
	         } else
	         {
	             sb.append(e.getMessage());
	         }
	         sb.append("<br>");

	         // Get the stack trace of the exception
	         sb.append("Exception Stack Trace = ");
	         StackTraceElement[] ste = e.getStackTrace();
	         for (int i = 0; i < ste.length; i++)
	         {
	             sb.append("<br>   at ");
	             sb.append(ste[i].toString());
	         }

	         // Get the stack trace of the exception cause
	         Throwable eCause = e.getCause();
	         if (eCause != null)
	         {
	             sb.append("<br><br>Exception Cause = ");
	             StackTraceElement[] ste1 = eCause.getStackTrace();
	             for (int i = 0; i < ste1.length; i++)
	             {
	                 sb.append("<br>   at ");
	                 sb.append(ste1[i].toString());
	             }
	         }

	         return sb.toString();
	     }
 
	 	 /**
	      * Sends data to the payment gateway via a POST. Parameters are received from the PaymentDetails
	      * object and the credit card parameters that have just been input by the customer are send in a
	      * separate list; the ccParmList
	      * 
	      * @param pd
	      * @param ccParmList
	      * @return The response to the post
	      * @throws IOException
	      */
	     public String postData(PaymentInfo pd, List<NameValue> ccParmList) throws IOException
	     {
	         URL url = new URL(pd.getRequesturl());
	         HttpURLConnection connection = (HttpURLConnection) url.openConnection();

	         connection.setRequestMethod("POST");
	         connection.setDoOutput(true);
	         connection.setDoInput(true);


	         customizeConnection(connection);

	         PrintWriter out = new PrintWriter(connection.getOutputStream());

	         StringBuffer sb = getGatewayRequest(pd, ccParmList);

	         if (log.isDebugEnabled())
	         {
	             log.debug("Post URL = " + pd.getRequesturl() + "\n");
	             log.debug("Post string = " + sb.toString() + "\n");

	             for (int i = 0; i < pd.getParameters().length; i++)
	             {
	                 NameValue nv = pd.getParameters()[i];
	                 log.debug(nv.getName() + " = " + nv.getValue());
	             }

	             for (Iterator<NameValue> iter = ccParmList.iterator(); iter.hasNext();)
	             {
	                 NameValue nv = iter.next();
	                 log.debug(nv.getName() + " = " + nv.getValue());
	             }
	         }

	         // Send the message
	         out.print(sb.toString());
	         out.close();

	         // Get back the response
	         StringBuffer respSb = new StringBuffer();
	         BufferedReader in = new BufferedReader(new InputStreamReader(connection.getInputStream()));
	         String line = in.readLine();

	         while (line != null)
	         {
	             respSb.append(line);
	             line = in.readLine();
	         }

	         in.close();

	         return respSb.toString();
	     }
	     
	     /**
	      * This method is normally specialized in the super class to customize the connection
	      * 
	      * @param connection
	      */
	     protected void customizeConnection(HttpURLConnection connection)
	     {
	     }
	     
	     /**
	      * This method can be specialized in the super class to customize the format of the request
	      * 
	      * @param pd
	      *            the PaymentDetails
	      * @param ccParmList
	      *            the credit card parameters
	      */
	     protected StringBuffer getGatewayRequest(PaymentInfo pd, List<NameValue> ccParmList)
	     {
	         // Create the message from the parameters in the PaymentDetails object
	         StringBuffer sb = new StringBuffer();
	         for (int i = 0; i < pd.getParameters().length; i++)
	         {
	        	 NameValue nv = pd.getParameters()[i];
	             if (i > 0)
	             {
	                 sb.append("&");
	             }
	             sb.append(nv.getName());
	             sb.append("=");
	             sb.append(nv.getValue());
	         }

	         // Add the credit card parameters
	         for (Iterator<NameValue> iter = ccParmList.iterator(); iter.hasNext();)
	         {
	        	 NameValue nv = iter.next();
	             sb.append("&");
	             sb.append(nv.getName());
	             sb.append("=");
	             sb.append(nv.getValue());
	         }

	         if (log.isDebugEnabled())
	         {
	             log.debug("GatewayRequest = \n" + sb);
	         }

	         return sb;
	     }
}
